home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 6 / MacMania 6.toast / / Tools&Utilities / EnterAct Stuff / Read Res project / Read_Res Source / Read_Res.c < prev   
Text File  |  1997-02-07  |  13KB  |  497 lines

  1. /* Read_Res.c - reads a specific resource from a file, and sends
  2. a formatted text version to the standard out file.
  3. Retrieves entire data fork if you specify resource type 'data', id 0.
  4. Shows hex and ascii values in a double-wide format. Note some example
  5. hAWK programs, eg $Print_MENU_Resource, illustrate analyzing the result
  6. from Read Resource - format the output, verify resource format. */
  7.  
  8. /* Copyright © 1991 the Free Software Foundation, Inc.
  9.  *         This file is free software; you can redistribute or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 1, or any later version.
  12.  *         This file is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15.  * GNU General Public License for more details.
  16.  *         You should have received a copy of the GNU General Public License
  17.  * along with GAWK; see the file "COPYING hAWK". If not, write to
  18.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  * Written for THINK C 4 on the Macintosh by Ken Earle (Dynabyte) Aug 1991.
  20.  */
  21.  
  22. #include <stdlib.h>
  23. #include <stdio.h>
  24. #include <string.h>
  25.  
  26. #include "CodeResource.h"
  27. #include "AppCodeComm.h"
  28. #include "CodeResHelper.h"
  29. #include "CodeResFiles.h"
  30.  
  31. //#if THINK_C >= 5
  32. //pascal void StringToNum(char *theString,long *theNum); 
  33. //pascal void NumToString(long theNum,char *theString);
  34. //#endif
  35.  
  36. #define LoadResID 406
  37. #define Cancel        2
  38.  
  39. short DoReadRes(void);
  40. Boolean ResForkIsAlreadyOpen(StringPtr fName, short vRefNum);
  41. Boolean SpecifyResource(long *theTypePtr, short *theIDPtr);
  42. Boolean BadIDNumber(char *idStr);
  43. Handle ReadTheResource(StringPtr namePtr, short vref, long theType, short theID);
  44. Handle ReadDataFork(StringPtr namePtr, short vref);
  45. Handle FixUpResource(Handle rawH);
  46. void WriteCharToOutput( char theChar);
  47. void JumpOnError(void);
  48. void DoExiting(void);
  49.  
  50.  
  51. /* Ask user to pick file, specify resource type and id. Print resource as hex
  52. and ascii to stdout. Return 1 (show resulting stdout) or -1 (error). */
  53. short DoReadRes()
  54.     {
  55.     Point         where;
  56.     SFReply     reply;
  57.     SFTypeList     types;
  58.     Handle         hText;
  59.     long         theType;
  60.     short            theID, ret = -1;
  61.  
  62.     // calculate where to put dialog, so that it'll be centered.
  63.     GetDlogOrigin (getDlgID, &where);
  64.     
  65.     do
  66.         {
  67.         SFGetFile (where, (StringPtr)"", NULL, -1, types, NULL, &reply);
  68.         } while (reply.good && ResForkIsAlreadyOpen((StringPtr)(reply.fName), reply.vRefNum));
  69.     
  70.     // If cancelled, forget it.
  71.     if (!reply.good)
  72.         {
  73.         DoExiting();
  74.         return(-1);
  75.         }
  76.     
  77.     // Ask user which resource to do.
  78.     if (!SpecifyResource(&theType, &theID))
  79.         {
  80.         DoExiting();
  81.         return(-1);
  82.         }
  83.     
  84.     SetWatchCursor();
  85.     
  86.     // Read in the resource and write it to stdout.
  87.     if (hText = ReadTheResource ((StringPtr)(reply.fName), reply.vRefNum,theType, theID))
  88.         {
  89.         hText = FixUpResource(hText);
  90.         if (hText)
  91.             {
  92.             if (PutToStdOut(hText))
  93.                 ret = 1;
  94.             DisposHandle(hText);
  95.             }
  96.         else
  97.             OKStopAlert("Not quite enough memory to do that, sorry.");
  98.         }
  99.     DoExiting();
  100.     return(ret);
  101.     }
  102.  
  103. /* Prelim assume that if youve seen one vref you've seen them all.
  104. Seems that PBGetFCBInfo never sets ioVRefNum, tho perhaps it
  105. pays attention to it...ioFCBVRefNum is for some reason set
  106. to the root of the disk. The awkward solution is to determine
  107. the owning directory ID of the file, and index thru open files,
  108. checking those that have the same dirID. */
  109. Boolean ResForkIsAlreadyOpen(StringPtr fName, short vRefNum)
  110.     {
  111.     
  112.     FCBPBRec    pb;
  113.     WDPBRec            theParms;
  114.     short            parentID;
  115.     char        fileName[32];
  116.     Boolean        resFAlreadyOpen = FALSE;
  117.     
  118.     theParms.ioVRefNum = vRefNum;
  119.     theParms.ioNamePtr = NULL;
  120.     theParms.ioWDIndex = 0;
  121.     theParms.ioWDProcID = 0;
  122.     if (PBGetWDInfo(&theParms, FALSE)) /* trouble of some kind */
  123.         return(TRUE);
  124.     parentID = theParms.ioWDDirID;
  125.     pb.ioCompletion = NULL;
  126.     pb.ioNamePtr = (StringPtr)fileName;
  127.     pb.ioVRefNum = vRefNum;
  128.     pb.ioRefNum = 0;
  129.     pb.ioFCBIndx = 1;
  130.     while (!PBGetFCBInfo(&pb, FALSE))
  131.         {
  132.         if ((short)(pb.ioFCBParID) == parentID)
  133.             {
  134.             if (PEqualStrs((Byte *)fileName, (Byte *)fName))
  135.                 {
  136.                 resFAlreadyOpen = TRUE;
  137.                 break;
  138.                 }
  139.             }
  140.         pb.ioVRefNum = vRefNum;
  141.         pb.ioRefNum = 0;
  142.         pb.ioFCBIndx += 1;
  143.         }
  144.     
  145.     if (resFAlreadyOpen)
  146.         {
  147.         OKStopAlert("Please avoid files that are already open.");
  148.         return(TRUE);
  149.         }
  150.     return(FALSE);
  151.     }
  152.  
  153. /* This should really have popup menus for the resource type and id. */
  154. Boolean SpecifyResource(long *theTypePtr, short *theIDPtr)
  155.     {
  156.     register DialogPtr        dPtr;
  157.     Ptr                        tempPtr;
  158.     short                    itemHit, theType, i, numTriesLeft;
  159.     Handle                    theItem;
  160.     Rect                    theBox;
  161.     char                    typeStr[10], idStr[10];
  162.     long                    idNum;
  163.  
  164.     InitCursor ();
  165.     
  166.     if (!GetAndAlignDialog(LoadResID))
  167.         return(FALSE);
  168.     dPtr = GetNewDialog (LoadResID, NULL, (WindowPtr)-1L);
  169.     numTriesLeft = 6;
  170.     FrameDialogItem(dPtr,1);
  171.     do{
  172.         --numTriesLeft;
  173.         SelIText (dPtr, 5, 0, 502);
  174.  
  175.     /* Give user a chance to change it and see if it's ok */
  176.         ModalDialog (NULL, &itemHit);
  177.         
  178.         if (itemHit == Cancel)
  179.             break;
  180.         
  181.         GetDItem (dPtr, 5, &theType, &theItem, &theBox);
  182.         GetIText (theItem, (StringPtr)typeStr);
  183.         GetDItem (dPtr, 6, &theType, &theItem, &theBox);
  184.         GetIText (theItem, (StringPtr)idStr);
  185.         StringToNum ((StringPtr)idStr, &idNum);
  186.     } while ((BadIDNumber(idStr) || typeStr[0] != 4) && numTriesLeft >= 0);
  187.  
  188.     
  189.     /* If cancelled, don't do anything */
  190.     if (itemHit == Cancel || numTriesLeft < 0)
  191.         {
  192.         DisposDialog (dPtr);
  193.         return(FALSE);
  194.         }
  195.     tempPtr = (Ptr)theTypePtr;
  196.     for (i = 0; i < 4; ++i)
  197.     *(tempPtr + i) = *(typeStr + i + 1);
  198.     
  199.     *theIDPtr = (short)idNum;
  200.     DisposDialog (dPtr);
  201.     return(TRUE);
  202.     }
  203.  
  204. /* Return TRUE if id number is BAD. 
  205. Leading white space not allowed.*/
  206. Boolean BadIDNumber(char *idStr)
  207.     {
  208.     short    i, len = idStr[0];
  209.     Boolean minusSeen = FALSE;
  210.     
  211.     if (len < 0 || len > 6) return(TRUE);
  212.     for (i = 1; i <= len; ++i)
  213.         {
  214.         if (idStr[i] == '-')
  215.             {
  216.             if ( i != 1)
  217.                 return(TRUE);
  218.             else
  219.                 minusSeen = TRUE;
  220.             }
  221.         else if (idStr[i] < '0' || idStr[i] > '9')
  222.             return(TRUE);
  223.         }
  224.     if (!minusSeen && len == 6) return(TRUE);
  225.     return(FALSE);
  226.     }
  227.  
  228. /* Get the specified resource. Due to overwhelming demand, also read in
  229. the data fork if wanted - this specified as 'data' id 0. */
  230. Handle ReadTheResource(StringPtr namePtr, short vref, long theType, short theID)
  231.     {
  232.     short     saveVol, refNum;
  233.     Handle    rsrcHandle, theHdle = NULL;
  234.     long            itemSize;
  235.     short                tempfNum;
  236.     
  237.     if (theType == 'data' && !theID) /* data fork requested */
  238.         return(ReadDataFork(namePtr, vref));
  239.     tempfNum = CurResFile();
  240.     
  241.     /* Remember default volume before changing it */
  242.     if (GetVol (NULL, &saveVol))
  243.         saveVol = 0;
  244.  
  245.     /* And set the volume.  This must be done because OpenResFile
  246.        looks only in current volume (directory).  Actually, it will
  247.        look along the Poor Man's Search Path, but this should do      */
  248.  
  249.     SetVol (NULL, vref);
  250.     SetResLoad(FALSE);
  251.     if ((refNum = OpenResFile (namePtr)) != -1)
  252.         {
  253.         SetResLoad(TRUE);
  254.         rsrcHandle = Get1Resource (theType, theID);
  255.  
  256.         if (rsrcHandle)
  257.             {
  258.             itemSize = GetHandleSize(rsrcHandle);
  259.             theHdle = NewHandle(itemSize);
  260.             if (MemError() == noErr)
  261.                 BlockMove(*rsrcHandle, *theHdle, itemSize);
  262.             else
  263.                 {
  264.                 ReleaseResource(rsrcHandle);
  265.                 CloseResFile (refNum);
  266.                 if (saveVol)
  267.                     SetVol (NULL, saveVol);
  268.                 UseResFile(tempfNum);
  269.                 
  270.                 OKStopAlert("Sorry, not enough memory to get the resource.");
  271.                 return(NULL);
  272.                 }
  273.             ReleaseResource(rsrcHandle);
  274.             }
  275.         else
  276.             OKStopAlert("Sorry, no resource with that type and ID. \
  277. Try using ResEdit to determine the correct type or number.");
  278.         CloseResFile (refNum);
  279.         }
  280.     else
  281.         {
  282.         SetResLoad(TRUE);
  283.         OKStopAlert("Sorry, couldn't open the resource fork \
  284. - maybe there isn't one?.");
  285.         }
  286.     /* Restore default volume if any */
  287.     if (saveVol)
  288.         SetVol (NULL, saveVol);
  289.     UseResFile(tempfNum);
  290.     
  291.     return(theHdle);
  292.     }
  293.  
  294. /* Read in the data fork to a handle. Note if there is
  295. nothing in the file then NULL is returned rather than an empty
  296. handle. */
  297. Handle ReadDataFork(StringPtr namePtr, short vref)
  298.     {
  299.     Handle        hText = NULL;
  300.     long        count;
  301.     short        saveVol, refNum;
  302.     Boolean        opened = FALSE;
  303.     
  304.     if (GetVol(NULL, &saveVol))
  305.         saveVol = 0;
  306.     if (FSOpen(namePtr, vref, &refNum))
  307.         goto JumpOut;
  308.     else
  309.         opened = TRUE;
  310.     if (GetEOF(refNum, &count) || count <= 0L)
  311.         goto JumpOut;
  312.     hText = NewHandle(count);
  313.     if (MemError() != noErr)
  314.         {
  315.         MemoryAlert();
  316.         goto JumpOut;
  317.         }
  318.     if (FSRead(refNum, &count, *hText))
  319.         {
  320.         DisposHandle(hText);
  321.         hText = NULL;
  322.         goto JumpOut;
  323.         }
  324. JumpOut:
  325.     if (opened)
  326.         FSClose(refNum);
  327.     if (saveVol)
  328.         SetVol(NULL, saveVol);
  329.     return(hText);
  330.     }
  331.  
  332. #include <ctype.h>
  333. #include <setjmp.h>
  334.  
  335. /* key code abbreviations - not all used here, but i thot you might like a list... */
  336. #define        ETX                '\003'        /* enter                 */
  337. #define        BS                '\b'        /* backspace            */
  338. #define        HT                '\t'        /* tab                    */
  339. #define        CR                0x0D        /* return                */
  340. #define        ESC                '\033'        /* clear                */
  341. #define        FS                '\034'        /* left arrow            */
  342. #define        GS                '\035'        /* right arrow            */
  343. #define        RS                '\036'        /* up arrow                */
  344. #define        US                '\037'        /* down arrow            */
  345. #define        COMMA            ','         /* or 0x2C */
  346. #define        BLANK            ' '         /* a space */
  347. #define        OPTBL            ' '            /* option-space */
  348. #define        COLON            ':'
  349. #define        FILLER            '.'        /* period, for nonascii char*/
  350.  
  351. #define    StdHdleInc    1024L
  352. static    long        outSize, privateTrueSize;
  353. static    Handle        outH;
  354.  
  355. /* buffer holding position of long jump */
  356. jmp_buf        LREnvBuf;
  357.  
  358. Handle FixUpResource(Handle rawH)
  359.     {
  360.     long        rawSize = GetHandleSize(rawH),
  361.                 startSize = 3*rawSize,
  362.                 rawPos = 0L;
  363.     Byte        *rawBPtr;
  364.     Ptr            rawPtr;
  365.     short        byteOff, i, numPads, numDigits;
  366.     char        rawChar, theChar, posStr[10];
  367.     Byte        rawBChar;
  368.     
  369.     MoveHHi(rawH);
  370.     HLock(rawH);
  371.     rawBPtr = (Byte *)(*rawH);
  372.     rawPtr = *rawH;
  373.     /* set up some convenient static stuff for creating new handle */
  374.     outSize = 0L;
  375.     privateTrueSize = 0L;
  376.     outH = NewHandle(startSize);
  377.     if (MemError() != noErr)
  378.         return(NULL);
  379.     privateTrueSize = startSize;
  380.     if (setjmp(LREnvBuf))
  381.         {
  382.         HUnlock(rawH);
  383.         DisposHandle(rawH);
  384.         DisposHandle(outH);
  385.         return(NULL);
  386.         }
  387.     /* output readable version of resource */
  388.     /* 16 bytes done per line; (8 hex space) 4 times, 16 ascii of same bytes. */
  389.     while (rawPos < rawSize)
  390.         {
  391.         /*WriteCharToOutput(HT); - for extra indent */
  392.         WriteCharToOutput(HT);
  393.         NumToString(rawPos, (StringPtr)posStr);
  394.         numDigits = posStr[0];
  395.         numPads = 5 - numDigits;
  396.         for (i = 0; i < numPads; ++i)
  397.             WriteCharToOutput(BLANK);
  398.         for (i = 1; i <= numDigits; ++i)
  399.             WriteCharToOutput(*(posStr + i));
  400.         WriteCharToOutput(COLON);
  401.         WriteCharToOutput(BLANK);
  402.         byteOff = 16;
  403.         if (rawPos + byteOff >= rawSize)
  404.             byteOff = rawSize - rawPos;
  405.         for (i = 0; i < byteOff; ++i)
  406.             {
  407.             if (i == 4 || i == 8 || i == 12)
  408.                 WriteCharToOutput(BLANK);
  409.             rawChar = *(rawPtr + rawPos + i);
  410.             if ((theChar = ((rawChar >>4) & 15)) <= 9)
  411.                 theChar += '0';
  412.             else
  413.                 theChar += 'A' - 10;
  414.             WriteCharToOutput(theChar);
  415.             if ((theChar = ((rawChar) & 15)) <= 9)
  416.                 theChar += '0';
  417.             else
  418.                 theChar += 'A' - 10;
  419.             WriteCharToOutput(theChar);
  420.             }
  421.         /* take care of the last short line - pad it out if necessary so that
  422.         text over on the right will still line up with the lines above.
  423.         Revision, after some anguish, pad the last line with zeroes rather
  424.         than blanks, to simplify manipulating the results with a hAWK program. */
  425.         for (; i < 16; ++i)
  426.             {
  427.             if (i == 4 || i == 8 || i == 12)
  428.                 WriteCharToOutput(BLANK);
  429.             WriteCharToOutput('0'); /* that's a zero */
  430.             WriteCharToOutput('0');
  431.             }
  432.         WriteCharToOutput(BLANK);
  433.         WriteCharToOutput(BLANK);
  434.         for (i = 0; i < byteOff; ++i)
  435.             {
  436.             rawBChar = *(rawBPtr + rawPos + i);
  437.             if (isprint(rawBChar))
  438.                 WriteCharToOutput((char)rawBChar);
  439.             else
  440.                 WriteCharToOutput(FILLER);
  441.             }
  442.             
  443.         rawPos += 16L;
  444.         WriteCharToOutput(CR);
  445.         }
  446.     
  447.     /* fix size of handle, dispose raw handle, return */
  448.     SetHandleSize(outH, outSize);
  449.     HUnlock(rawH);
  450.     DisposHandle(rawH);
  451.     return(outH);
  452.     }
  453.  
  454. void WriteCharToOutput( char theChar)
  455.     {
  456.     
  457.     if (outSize >= privateTrueSize)
  458.         {
  459.         SetHandleSize(outH, privateTrueSize + StdHdleInc);
  460.         if (MemError() != noErr)
  461.             JumpOnError();
  462.         privateTrueSize += StdHdleInc;
  463.         }
  464.     *(*outH + outSize++) = theChar;
  465.     }
  466.  
  467. void JumpOnError()
  468.     {
  469.     
  470.     longjmp(LREnvBuf, 1); /* return to save point */
  471.     }
  472.  
  473. static pascal void EmptyExitToShell(void);
  474. enum
  475.     {
  476.     uppExitToShellProcInfo = kPascalStackBased
  477.     };
  478. // Patch ExitToShell out temporarily and call exit()
  479. void DoExiting(void)
  480.     {
  481.     pascal void (*gOldExitToShell)(void);
  482.     UniversalProcPtr EmptyExitToShellProcPtr;
  483.     
  484.     gOldExitToShell = (void *)GetToolTrapAddress(0xA9F4);
  485.     EmptyExitToShellProcPtr = NewRoutineDescriptor((ProcPtr)&EmptyExitToShell,
  486.                                     uppExitToShellProcInfo,
  487.                                     GetCurrentISA());
  488.     SetToolTrapAddress(EmptyExitToShellProcPtr, 0xA9F4);
  489.     exit(0);
  490.     SetToolTrapAddress((UniversalProcPtr)gOldExitToShell, 0xA9F4);
  491.     }
  492.  
  493. static pascal void EmptyExitToShell(void)
  494.     {
  495.     ;
  496.     }
  497.